"""Tests for terminal_utils module."""

import pytest

from mini_agent.utils import (
    calculate_display_width,
    pad_to_width,
    truncate_with_ellipsis,
)


class TestCalculateDisplayWidth:
    """Tests for calculate_display_width function."""

    def test_ascii_text(self):
        """Test ASCII text width calculation."""
        assert calculate_display_width("Hello") == 5
        assert calculate_display_width("World") == 5
        assert calculate_display_width("Test 123") == 8

    def test_empty_string(self):
        """Test empty string."""
        assert calculate_display_width("") == 0

    def test_emoji(self):
        """Test emoji width (should count as 2)."""
        assert calculate_display_width("🤖") == 2
        assert calculate_display_width("💭") == 2
        assert calculate_display_width("🤖 Agent") == 8  # 2 + 1 + 5

    def test_chinese_characters(self):
        """Test Chinese characters (each counts as 2)."""
        assert calculate_display_width("你好") == 4
        assert calculate_display_width("你好世界") == 8
        assert calculate_display_width("中文") == 4

    def test_japanese_characters(self):
        """Test Japanese characters."""
        assert calculate_display_width("日本語") == 6  # 3 chars * 2

    def test_mixed_content(self):
        """Test mixed ASCII and wide characters."""
        assert calculate_display_width("Hello 你好") == 10  # 5 + 1 + 4
        assert calculate_display_width("Test 🤖") == 7  # 4 + 1 + 2

    def test_ansi_codes_ignored(self):
        """Test that ANSI escape codes are not counted."""
        colored = "\033[31mRed\033[0m"
        assert calculate_display_width(colored) == 3

        colored_emoji = "\033[31m🤖\033[0m"
        assert calculate_display_width(colored_emoji) == 2

    def test_combining_characters(self):
        """Test combining characters (should not add width)."""
        # é = e + combining acute accent
        e_with_accent = "e\u0301"
        assert calculate_display_width(e_with_accent) == 1

    def test_complex_ansi_sequences(self):
        """Test complex ANSI sequences."""
        text = "\033[1m\033[36mBold Cyan\033[0m"
        assert calculate_display_width(text) == 9  # "Bold Cyan"


class TestTruncateWithEllipsis:
    """Tests for truncate_with_ellipsis function."""

    def test_no_truncation_needed(self):
        """Test when text fits within width."""
        assert truncate_with_ellipsis("Hello", 10) == "Hello"
        assert truncate_with_ellipsis("Test", 5) == "Test"

    def test_exact_fit(self):
        """Test when text exactly fits."""
        assert truncate_with_ellipsis("Hello", 5) == "Hello"

    def test_ascii_truncation(self):
        """Test truncation of ASCII text."""
        assert truncate_with_ellipsis("Hello World", 8) == "Hello W…"
        assert truncate_with_ellipsis("Testing", 4) == "Tes…"

    def test_chinese_truncation(self):
        """Test truncation with Chinese characters."""
        result = truncate_with_ellipsis("你好世界", 5)
        # Should be: 你好 (4 width) + … (1 width) = 5
        assert calculate_display_width(result) <= 5
        assert "…" in result

    def test_emoji_truncation(self):
        """Test truncation with emoji."""
        result = truncate_with_ellipsis("🤖🤖🤖", 3)
        # Should be: 🤖 (2 width) + … (1 width) = 3
        assert calculate_display_width(result) <= 3

    def test_zero_width(self):
        """Test with zero width."""
        assert truncate_with_ellipsis("Hello", 0) == ""

    def test_width_one(self):
        """Test with width of 1."""
        result = truncate_with_ellipsis("Hello", 1)
        assert len(result) <= 1

    def test_ansi_codes_removed(self):
        """Test that ANSI codes are removed during truncation."""
        colored = "\033[31mHello World\033[0m"
        result = truncate_with_ellipsis(colored, 8)
        # ANSI codes should be removed
        assert "\033[" not in result
        assert "…" in result


class TestPadToWidth:
    """Tests for pad_to_width function."""

    def test_left_align(self):
        """Test left alignment (default)."""
        result = pad_to_width("Hello", 10)
        assert result == "Hello     "
        assert len(result) == 10

    def test_right_align(self):
        """Test right alignment."""
        result = pad_to_width("Hello", 10, align="right")
        assert result == "     Hello"
        assert len(result) == 10

    def test_center_align(self):
        """Test center alignment."""
        result = pad_to_width("Test", 10, align="center")
        assert result == "   Test   "
        assert len(result) == 10

    def test_center_align_odd(self):
        """Test center alignment with odd padding."""
        result = pad_to_width("Hi", 7, align="center")
        # Should be: "  Hi   " or "   Hi  " (either is acceptable)
        assert "Hi" in result
        assert len(result) == 7

    def test_chinese_padding(self):
        """Test padding with Chinese characters."""
        result = pad_to_width("你好", 10)
        # "你好" is 4 display width, so needs 6 spaces
        assert calculate_display_width(result) == 10

    def test_emoji_padding(self):
        """Test padding with emoji."""
        result = pad_to_width("🤖", 10)
        # "🤖" is 2 display width, so needs 8 spaces
        assert calculate_display_width(result) == 10

    def test_no_padding_needed(self):
        """Test when text already reaches target width."""
        result = pad_to_width("Hello", 5)
        assert result == "Hello"

    def test_text_exceeds_width(self):
        """Test when text exceeds target width."""
        result = pad_to_width("Hello World", 5)
        assert result == "Hello World"  # No truncation, just return as-is

    def test_invalid_align(self):
        """Test invalid alignment value."""
        with pytest.raises(ValueError, match="Invalid align value"):
            pad_to_width("Test", 10, align="invalid")

    def test_custom_fill_char(self):
        """Test custom fill character."""
        result = pad_to_width("Test", 10, fill_char="-")
        assert result == "Test------"


class TestRealWorldScenarios:
    """Tests for real-world usage scenarios."""

    def test_step_header(self):
        """Test Step header formatting (from agent.py)."""
        step = 1
        max_steps = 50
        step_text = f"💭 Step {step}/{max_steps}"

        width = calculate_display_width(step_text)
        # "💭" (2) + " Step 1/50" (10) = 12
        assert width == 12

    def test_session_info_model(self):
        """Test Session Info model line."""
        model = "minimax-01"
        line = f"Model: {model}"
        width = calculate_display_width(line)
        # Should calculate correctly regardless of model name
        assert width > 0

    def test_chinese_model_name(self):
        """Test with Chinese model name."""
        model = "模型-01"
        line = f"Model: {model}"
        width = calculate_display_width(line)
        # "Model: " (7) + "模型-01" (2+2+3) = 14
        assert width == 14

    def test_banner_text(self):
        """Test banner text from cli.py."""
        banner = "🤖 Mini Agent - Multi-turn Interactive Session"
        width = calculate_display_width(banner)
        # "🤖" (2) + " Mini Agent - Multi-turn Interactive Session" (44) = 46
        assert width == 46
